rlc - RmbRT Compiler

The RmbRT compiler is not just a compiler, but a whole toolkit of developer tools. It contains a code/package management system, a compilation cache, a VM for debugging and scripting, JIT compilers, a linker, and more.

Resource management

RmbRT resources, such as a source file, a project/package, or a compiled executable or library, are tracked by the RmbRT compiler. This is done to facilitate version control, dependency management, compilation caching, provable compilation, etc. globally. All these things are taken care of by the compiler to allow for a standardised development environment and ease of use.

Projects and project ecosystem

A RmbRT project is identified not by its name in a file system, but by a globally unique identifier. This allows tracking a project even after it has been rebranded. This ID is randomly generated by the compiler when creating a new project.

rlc project new <name>

All RmbRT projects together form a decentralised ecosystem, and their unique IDs are needed to tell apart projects with the same name by different authors. Later on, the compiler will also integrate with a peer-to-peer network for decentralised code hosting and attestable compilation. This will make the projects and dependency management robust, as no centralised service will be needed for fetching code, and dependency locators will not expire.

A project tracks all of the project's source files, as well as all projects the project depends on. Projects have an inbuilt version system that keeps track of the source file hashes for both caching and version control independent of sub-version tools such as git. This allows projects to specify exact versions of dependencies. The project's properties are accessible from inside a RmbRT program's build environment, which easily allows programs to print their source version, build date, project ID, and more in a generic way.

Caching

The hashes of sources are cached together with their resulting output binaries. This allows for quick compilation times when including common dependencies, such as the standard library. Later on, the peer-to-peer network will allow fetching verified cached output binaries from other peers, which will help reduce compilation times for large projects or on slow devices.

Versioning and dependencies

The compiler uses the following versioning system, derived from semantic versioning: releases are grouped into super.major.minor.patch versions (such as 1.0.3.5). Patches fix broken functionality or improve performance and stability, minor releases add new functionality, major releases break some interfaces, and super releases mark a complete overhaul of the project's structure or functionality. Updating a dependency to a new patch or minor revisions should not break a project, and even improve stability. When updating to a new major revision, some minor problems are allowed, but if an upgrade would require great changes in dependent projects, such as changes in the overall architecture, then a super release should be made.

With just revision numbers alone, the system is impractical, however, since development versions might quickly get to high major and super revisions. Therefore, there are also streams, which can give additional context to releases, for example the default stream for official releases is master, and other streams could be dev, staging, etc. Thus, a stream gives context to the version, and the master stream should update in more coarse-grained increments than staging streams. For example, when prototyping a project, the developers can work on stream prototype and do many overhauls before deciding to release the official version 1.0.0.0. Then, prototype 6.3.6.9 might equal master 1.0.0.0.

Instead of tracking the changes made between versions, the RmbRT compiler only pins the current version's hash digest in the project file. The version counter is concurrency-safe, so that when two minor version updates are made on forks, they can be merged and will result in a correctly summed version increment in the upstream repository. This only works for minor versions and patches, though. Use rlc release merge to resolve merge conflicts in the project file resulting from concurrent releases.

rlc release stage <stream> super|major|minor|[patch]
rlc release merge
rlc release publish <stream>
rlc import <project ID> [<stream>] [min <version>] [max <version>]
rlc import <project ID> [<stream>] <version>
rlc update-deps super|major|[minor]|patch

This versioning system allows parallel development streams but explicitly forbids versioning uncertainties that arise when publishing parallel changes of differing release scale. When importing with version constraints, then rlc update-deps will update all dependencies to their newest available version that is still within the specified range. When no constraints are used for an import, then it just updates the dependency to its newest available version. Updating can also selectively target minor or patch increments only, to prevent pulling any breaking changes.

All new projects start with version master 0.0.0.0. For all work that is not intended to be used directly by other projects, a development stream should be used.